/*
 * DLL wrapper for the MockModel (ModelSimulator) class
 *
 * Copyright (C) 2010 Johan Waldeback
 *  
 * This file is part of the OpenFMS project (http://www.openfms-project.org)
 * 
 * OpenFMS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * \file MockModel_dllexport.cpp
 * \brief DLL wrapper for the MockModel class
 *
 * The DLL has five public functions: \c create, \c destroy, \c getinertias, \c setstepsize and \c step:
 *  - \c create Creates a new instance of a MockModel class, and calles \c MockModel::create
 *  - \c destroy Deletes an instnce of a MockModel class, after having called \c MockModel::destory
 *  - \c getinertias Calles \c MockModel::getInertias 
 *  - \c setstepsize Calles \c MockModel::setStepSize
 *  - \c step Calles \c MockModel::setp
 */

#include "MockModel.h"
using namespace OpenFms;



//
// THE DLL INTERFACE
//

extern "C" {

/**
 * Create and setup an instance a MockModel class
 *
 * This function creates a MockModel class, then calles its load function. The returned
 * value is a handle representing that instance.
 *
 * @param _read_fn Read callback function to be passed on to \c MockModel::load
 * @param _custom Custom variable to be passed on to \c MockModel::load
 * @return If successful, returns a handle representing the created instance. Otherwise returns 0.
 */
__declspec(dllexport) 
ModelSimulator_handle_t create(ModelSimulator_read_callback_t _read_fn, uint64_t _custom)
{
    // create a class instance
    MockModel *pResult = new MockModel();
    if(!pResult) return 0;

    // create the actual object
    // retrun  pointer to the class instance if success
    if(pResult->create(_read_fn, _custom)) return reinterpret_cast<ModelSimulator_handle_t>(pResult);

    // if here, then fail
    delete pResult; // cleanup
    return 0;
}

/**
 * Calles \c MockModel::destroy and then frees the MockModel instance
 * @param _handle A handle retruned by a previous call to \c create.
 * @return Returns zero if \c MockModel::destroy returns succes. Retruns non-zero otherwise.
 */
__declspec(dllexport) 
uint32_t destroy(ModelSimulator_handle_t _handle)
{
    if(_handle) {
        MockModel *p = reinterpret_cast<MockModel *>(_handle);
        p->destroy();
        delete p;
    }
    return 0;
}

/**
 * Calles \c MockModel::getInertias
 * @param _handle A handle retruned by a previous call to \c create.
 * @param _inertias Pointer to a ModelSimulator_inertias_t to be passed on to \c MockModel::getInertias.
 * @return Returns zero if \c MockModel::getInertias returns succes. Retruns non-zero otherwise.
 */
__declspec(dllexport) 
uint32_t getinertias(ModelSimulator_handle_t _handle, uint64_t _inertias)
{
    // 1. check input arguments
    // 2. call the corresponding function in the class (doing nessesary castings)
    // 3. return 0 if success, 1 if fail.
    if(_handle && _inertias) {
        if(reinterpret_cast<MockModel *>(_handle)->getInertias(*reinterpret_cast<ModelSimulator_inertias_t *>(_inertias))) return 0;
    }
    // if here, them failed;
    return 1;
}

/**
 * Calles \c MockModel::setStepSize
 * @param _handle A handle retruned by a previous call to \c create.
 * @param _stepSize Value to be passed on to \c MockModel::setStepSize.
 * @return Returns zero if \c MockModel::setStepSize returns succes. Retruns non-zero otherwise.
 */
__declspec(dllexport) 
uint32_t setstepsize(ModelSimulator_handle_t _handle, float _stepSize)
{
    // 1. check input arguments
    // 2. call the corresponding function in the class (doing nessesary castings)
    // 3. return 0 if success, 1 if fail.
    if(_handle) {
        if(reinterpret_cast<MockModel *>(_handle)->setStepSize(_stepSize)) return 0;
    }
    // if here, them failed;
    return 1;
}

/**
 * Calles \c MockModel::step
 * @param _handle A handle retruned by a previous call to \c create.
 * @param _environment Pointer to a ModelSimulator_environment_t to be passed on to \c MockModel::step.
 * @param _forces Pointer to a ModelSimulator_forces_t to be passed on to \c MockModel::step.
 * @return Returns zero if \c MockModel::step returns succes. Retruns non-zero otherwise.
 */
__declspec(dllexport) 
uint32_t step(ModelSimulator_handle_t _handle, uint64_t _environment, uint64_t _forces)
{
    // 1. check input arguments
    // 2. call the corresponding function in the class (doing nessesary castings)
    // 3. return 0 if success, 1 if fail.
    if(_handle) {
        if(reinterpret_cast<MockModel *>(_handle)->step(
            *reinterpret_cast<ModelSimulator_environment_t *>(_environment),
            *reinterpret_cast<ModelSimulator_forces_t *>(_forces)
        )) return 0;
    }
    // if here, them failed;
    return 1;
}

} // extern "C"
